package br.com.cfccultura.admin.control.actions.cadastros;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import br.com.cfccultura.admin.control.actions.DefaultAction;
import br.com.cfccultura.admin.control.forms.cadastros.CadastroTurmaForm;
import br.com.cfccultura.admin.control.utils.CalculoDataTurma;
import br.com.cfccultura.admin.control.utils.CarregaComboAjax;
import br.com.cfccultura.admin.model.enums.DiaSemana;
import br.com.cfccultura.admin.model.enums.Periodo;
import br.com.cfccultura.admin.model.enums.SimNao;
import br.com.cfccultura.admin.model.enums.TipoFuncionario;
import br.com.cfccultura.admin.model.enums.TipoPeriodo;
import br.com.cfccultura.admin.model.vo.Aluno;
import br.com.cfccultura.admin.model.vo.AvaliacaoCurso;
import br.com.cfccultura.admin.model.vo.CalendarioDia;
import br.com.cfccultura.admin.model.vo.ContaReceber;
import br.com.cfccultura.admin.model.vo.Curso;
import br.com.cfccultura.admin.model.vo.Funcionario;
import br.com.cfccultura.admin.model.vo.Matricula;
import br.com.cfccultura.admin.model.vo.OrdemServico;
import br.com.cfccultura.admin.model.vo.Sala;
import br.com.cfccultura.admin.model.vo.Turma;
import br.com.cfccultura.admin.view.report.ReportManager.Type;
import br.com.cfccultura.admin.view.report.helper.TaxiDetailHelper;

@Component("/cadastroTurma")
public class CadastroTurmaAction extends DefaultAction {
	
	private static final Logger logger = Logger.getLogger(CadastroTurmaAction.class); 

	@Autowired
	private CalculoDataTurma calculoDataTurma;
	
	public ActionForward iniciar(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {		
		
		CadastroTurmaForm turmaForm = (CadastroTurmaForm) form;
		consultar(turmaForm, request);
		
		return mapping.findForward("body");
	}
	
	public ActionForward consultar(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {		
		
		CadastroTurmaForm turmaForm = (CadastroTurmaForm) form;
		consultar(turmaForm, request);
		
		return mapping.findForward("body");
	}
	
	public ActionForward detalhe(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {		
		
		CadastroTurmaForm turmaForm = (CadastroTurmaForm) form;
		Turma turma = getTurmaDAO().consultar(turmaForm.getIdSelecionado());
		
		Boolean matriculasAvaliadas = true;
		for(Matricula matricula : turma.getMatriculas()) {
			Aluno aluno = getAlunoDAO().consultar(matricula.getAluno().getCodigo());
			matricula.setAluno(aluno);			
			
			OrdemServico os = getOrdemServicoDAO().consultar(matricula.getOrdemServico().getCodigo());
			List<ContaReceber> debitos = getFluxoCaixaDAO().verificaDebito(matricula.getOrdemServico());
			matricula.setOrdemServico(os);
			
			double totalPago = 0D;
			for(ContaReceber receber : debitos) {
				totalPago += receber.getValorPagamento();
			}
			if(totalPago < os.getTotal()) {
				os.setDevedor(os.getTotal() - totalPago);
			}
			
			if(matricula.getAvaliacao() == null) {
				matriculasAvaliadas = false;
			}
		}
		
		if(turma.getMatriculas().size() == 0)
			matriculasAvaliadas = false;
		
		if(turma.getCurso().getCodigo() == 4 && matriculasAvaliadas) { //Taxi
			request.setAttribute("emitirTermoCredenciamentoTaxi", true);
		}
		
		request.setAttribute("turmaDetalhe", turma);
		
		return mapping.findForward("detalhe");
	}
	
	public ActionForward incluir(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {		
		
		CadastroTurmaForm turmaForm = (CadastroTurmaForm) form;
		Turma vo = new Turma();
		vo.setInicio(getDateFormat().parse(turmaForm.getDataInicio()));
		vo.setPeriodo(Periodo.valueOf(turmaForm.getPeriodo()));
		vo.setCurso(getCursoDAO().consultar(turmaForm.getCurso()));
		vo.setSala(new Sala(turmaForm.getSala()));
		vo.setInstrutor(new Funcionario(turmaForm.getInstrutor()));
		vo.setUsuarioSistema(getUsuario(request));
		
		List<CalendarioDia> calendario = getCalculoDataTurma().getDataTermino(vo);
		calendario.add(0, new CalendarioDia(vo.getInicio()));
		
		vo.setTermino(calendario.get(calendario.size() -1).getData());
		vo.setCalendario(calendario);
		
		getTurmaDAO().incluir(vo);
		
		return null;
	}
	
	public ActionForward alterarIniciar(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {		
		
		CadastroTurmaForm turmaForm = (CadastroTurmaForm) form;
		Turma vo = getTurmaDAO().consultar(turmaForm.getIdSelecionado());
		
		Object[] params = null;
		
		if(vo.getEncerrado()) {
			params = new Object[] {false, "Turma já encerrada. Não é possivel alterar!"};
		} else {
			params = new Object[] {
				true,
				vo.getCurso().getCodigo(),
				vo.getPeriodo().name(),
				getDateFormat().format(vo.getInicio()),
				vo.getSala().getCodigo(),
				vo.getInstrutor().getCodigo()
			};
		}
		
		printJsonObjectToStream(params, response);
		
		return null;
	}	
	
	public ActionForward alterar(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {		
		
		CadastroTurmaForm turmaForm = (CadastroTurmaForm) form;
		Turma vo = new Turma();
		vo.setCodigo(turmaForm.getIdSelecionado());
		vo.setInicio(getDateFormat().parse(turmaForm.getDataInicio()));
		vo.setPeriodo(Periodo.valueOf(turmaForm.getPeriodo()));
		vo.setCurso(getCursoDAO().consultar(turmaForm.getCurso()));
		vo.setSala(new Sala(turmaForm.getSala()));
		vo.setInstrutor(new Funcionario(turmaForm.getInstrutor()));
		vo.setUsuarioSistema(getUsuario(request));
		
		List<CalendarioDia> calendario = getCalculoDataTurma().getDataTermino(vo);
		calendario.add(0, new CalendarioDia(vo.getInicio()));
		
		vo.setTermino(calendario.get(calendario.size() -1).getData());
		vo.setCalendario(calendario);
		
		getTurmaDAO().alterar(vo);
		
		return null;
	}
	
	public ActionForward excluir(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {		
		
		CadastroTurmaForm turmaForm = (CadastroTurmaForm) form;
		Object[] params = {true, ""};
		
		Turma turma = getTurmaDAO().consultar(turmaForm.getIdSelecionado());
		if(turma.getEncerrado()) {
			params = new Object[] {false, "Turma já encerrada. Não é possivel alterar!"};
		} else if(turma.getMatriculas().size() > 0) {
			params = new Object[]{false, "Não é possível excluir está Turma.\n Há " + turma.getMatriculas().size() + " aluno(s) matriculado(s)."};
		} else {		
			getTurmaDAO().excluir(turmaForm.getIdSelecionado());
		}		
		
		printJsonObjectToStream(params, response);		
		return null;
	}
	
	public ActionForward carregaPeriodoCurso(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {		
		
		CadastroTurmaForm turmaForm = (CadastroTurmaForm) form;
		
		Curso curso = getCursoDAO().consultar(turmaForm.getCurso());
		List<Periodo> list = new CarregaComboAjax().loadComboPeriodo(curso.getTipoPeriodo());
		
		Object[] params = {true, list};
		printJsonObjectToStream(params, response);
		
		return null;
	}
	
	public ActionForward consultaProximaDisponivel(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {		
		
		CadastroTurmaForm turmaForm = (CadastroTurmaForm) form;
		
		Turma vo = new Turma();
		vo.setCurso(new Curso(turmaForm.getCurso()));
		vo.setInicio(new Date());
		
		List<Turma> list = getTurmaDAO().consultar(vo);
		
		Object[] turmas = new Object[list.size()];
		int i = 0;
		for(Turma turma : list) {
			Object[] dados = {
				turma.getCodigo(),
				getDateFormat().format(turma.getInicio()) + " - " + getDateFormat().format(turma.getTermino()) + " - " + turma.getPeriodo().getDescricao()
			};
			turmas[i++] = dados;
		}
		
		Object[] params = {true, turmas};
		
		if(list.size() == 0) {
			params[0] = false;
			params[1] = "Não há turmas disponiveis. Favor realizar o cadastro de turmas.";
		}
		
		printJsonObjectToStream(params, response);
		
		return null;
	}	
	
	public ActionForward verificaData(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {		
		
		CadastroTurmaForm turmaForm = (CadastroTurmaForm) form;
		
		Date dataInformada = getDateFormat().parse(turmaForm.getDataInicio());
		Curso curso = getCursoDAO().consultar(turmaForm.getCurso());
		Periodo periodo = Periodo.valueOf(turmaForm.getPeriodo());
		
		Turma turmaAlterar = null;
		
		if(request.getParameter("funcao").equals("alterar")) {
			turmaAlterar = getTurmaDAO().consultar(turmaForm.getIdSelecionado());
		}
		
		/*
		 * Consulta se o dia selecionado é válido.
		 */
		CalendarioDia dia = getCalendarioDAO().consultar(dataInformada);
		
		Object[] params = {true, "", "", ""};
		
		if(dia == null) {
			params[0] = false;
			params[1] = "Dia " + getDateFormat().format(dataInformada) + " não previsto no Calendário do Sistema.\nFavor informar ao Administrador!";			
		} else if(dia.getFeriado().equals(SimNao.SIM)) {
			params[0] = false;
			params[1] = "Dia " + getDateFormat().format(dia.getData()) + " é Feriado: " + dia.getDescricao();
		} else {
			if(curso.getTipoPeriodo().equals(TipoPeriodo.DIA_UTIL) && dia.getDiaSemana().isFinalSemana()) {
				params[0] = false;
				params[1] = "Para o curso selecionado, a turma deverá ser apenas em dias uteis!\nSelecione uma nova data!";				
			} else if(curso.getTipoPeriodo().equals(TipoPeriodo.FINAL_SEMANA) && !dia.getDiaSemana().isFinalSemana()) {
				params[0] = false;
				params[1] = "Para o curso selecionado, a turma deverá ser apenas em final de semana!\nSelecione uma nova data!";
			} else if(curso.getTipoPeriodo().equals(TipoPeriodo.FINAL_SEMANA) && dia.getDiaSemana().isFinalSemana()) {
				if(periodo.equals(Periodo.SABADO) && !dia.getDiaSemana().equals(DiaSemana.SABADO)) {
					params[0] = false;
					params[1] = "Data Inválida!\n Favor selecionar no calendário um SABADO!";					
				} else 	if(periodo.equals(Periodo.DOMINGO) && !dia.getDiaSemana().equals(DiaSemana.DOMINGO)) {
					params[0] = false;
					params[1] = "Data Inválida!\n Favor selecionar no calendário um DOMINGO!";
				} else 	if(periodo.equals(Periodo.SABeDOM) && !dia.getDiaSemana().equals(DiaSemana.SABADO)) {
					params[0] = false;
					params[1] = "Data Inválida!\n Favor selecionar no calendário um SABADO!";
				}
			}
		}
		
		List<Sala> salaDisponivelList = new ArrayList<Sala>();
		List<Sala> salas = getSalaAulaDAO().consultar(new Sala());
		
		List<Funcionario> instrutorDisponivelList = new ArrayList<Funcionario>();
		List<Funcionario> instrutores = getFuncionarioDAO().consultar(new Funcionario(TipoFuncionario.INSTRUTOR));
		
		Turma turma = new Turma();
		turma.setInicio(dataInformada);
		turma.setTermino(dataInformada);
		List<Turma> list = getTurmaDAO().consultar(turma);
		
		if(list.size() > 0) {
			
			Turma t1 = list.get(0);	
			
			for(Sala sala : salas) {
				boolean salaDisponivel = true;
				l2:for(Turma t2 : list) {
					if(sala.getCodigo().equals(t2.getSala().getCodigo())) {
						if(t1.getPeriodo().isFinalSemana() || t1.getPeriodo().equals(periodo)) {
							salaDisponivel = false;
							break l2;
						}
					}
				}
				if(salaDisponivel) {
					salaDisponivelList.add(sala);
				} else {
					if(turmaAlterar != null) {
						if(sala.getCodigo() == turmaAlterar.getSala().getCodigo()) {
							salaDisponivelList.add(sala);
						}
					}
				}
			}
			
			for(Funcionario instrutor : instrutores) {
				boolean instrutorDisponivel = true;
				l2:for(Turma t2 : list) {
					if(instrutor.getCodigo().equals(t2.getInstrutor().getCodigo())) {
						if(t1.getPeriodo().isFinalSemana() || t1.getPeriodo().equals(periodo)) {
							instrutorDisponivel = false;
							break l2;
						}
						
					}
				}
				if(instrutorDisponivel) {
					instrutorDisponivelList.add(instrutor);
				} else {
					if(turmaAlterar != null) {
						if(instrutor.getCodigo() == turmaAlterar.getInstrutor().getCodigo()) {
							instrutorDisponivelList.add(instrutor);		
						}
					}
				}
			}
		} else {
			salaDisponivelList.addAll(salas);
			instrutorDisponivelList.addAll(instrutores);
		}		
		
		params[2] = salaDisponivelList;
		params[3] = instrutorDisponivelList;
		
		printJsonObjectToStream(params, response);
		
		return null;
	}
	
	public ActionForward atualizarAvaliacao(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {		
		
		CadastroTurmaForm turmaForm = (CadastroTurmaForm) form;
		
		Integer matricula = turmaForm.getIdSelecionado();
		
		getTurmaDAO().atualizarAvaliacao(matricula, new AvaliacaoCurso(turmaForm.getAvaliacao()));
		
		return null;		
	}
	
	public ActionForward gerarRelacaoAlunosTaxi(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		CadastroTurmaForm turmaForm = (CadastroTurmaForm) form;
		Turma turma = getTurmaDAO().consultar(turmaForm.getIdSelecionado());
		
		if(turma.getCodigoTaxi() == null) {
			getTurmaDAO().gerarTurmaTaxi(turma);
			turma = getTurmaDAO().consultar(turmaForm.getIdSelecionado());
		}
		
		String codigoTurma = turma.getCodigoTaxi().toString();
		while(codigoTurma.length() < 5) {
			codigoTurma = "0" + codigoTurma;
		}
		
		StringBuilder arquivo = new StringBuilder();
		for(Matricula matricula : turma.getMatriculas()) {
			arquivo.append("029T");
			arquivo.append(codigoTurma);
			
			String cpf = matricula.getAluno().getCpf().toString();
			cpf = cpf.replaceAll("\\D", "");

			arquivo.append(cpf);
			arquivo.append("T");
			arquivo.append(getDateFormat().format(turma.getTermino()));
			
			String codigoMatricula = matricula.getCodigoTaxi().toString();
			while(codigoMatricula.length() < 8) {
				codigoMatricula = "0" + codigoMatricula;
			}
			arquivo.append(codigoMatricula);
			arquivo.append("C");
			arquivo.append("\n");
		}
		
		response.setContentType("text/text");
        response.addHeader("Content-disposition", "attachment; filename=\"RelacaoAlunos-turma" + turma.getCodigo() + ".txt\"");
		IOUtils.write(arquivo, response.getOutputStream(), "UTF-8");
		return null;		
	}
	
	public ActionForward gerarCertificados(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		CadastroTurmaForm turmaForm = (CadastroTurmaForm) form;
		List<Matricula> matriculas = new ArrayList<Matricula>();
		
		Date dataInicio = null;
		Date dataTermino = null;
		
		if(turmaForm.getIdSelecionado() != null && turmaForm.getIdSelecionado() > 0) {
			Turma turma = getTurmaDAO().consultar(turmaForm.getIdSelecionado());
			matriculas.addAll(turma.getMatriculas());
			dataInicio = turma.getInicio();
			dataTermino = turma.getTermino();
		} else if(turmaForm.getMatricula() != null && turmaForm.getMatricula() > 0) {
			Matricula m = getTurmaDAO().consultarMatricula(new Matricula(turmaForm.getMatricula()));
			matriculas.add(m);
			dataInicio = m.getTurma().getInicio();
			dataTermino = m.getTurma().getTermino();
		}
		
		
		
		List<TaxiDetailHelper> helper = new ArrayList<TaxiDetailHelper>();
		
		for(Matricula matricula : matriculas) {
			
			StringBuilder descricao = new StringBuilder();
			descricao.append("Certificamos que ").append(matricula.getAluno().getNome().toUpperCase() + " portador(a) do CPF.").append(matricula.getAluno().getCpf());
			descricao.append(" concluiu com aproveitamento o curso de TAXI COMUM com duração de 32 horas/aula, realizado no período de ");
			descricao.append(getDateFormat().format(dataInicio)).append(" à ").append(getDateFormat().format(dataTermino)).append(".");
			helper.add(new TaxiDetailHelper(descricao.toString(), matricula.getAluno().getCpf()));
		}
		
		HashMap<String, Object> params = new HashMap<String, Object>();
		params.put("dataExtensoFormatada", String.format(new Locale("pt","BR"), "São Paulo, %1$td de %1$tB de %1$tY", new Date()));
		
		request.getSession().setAttribute("reportType", Type.CERTIFICADO_TAXI);
		request.getSession().setAttribute("jasperParams", params);
		request.getSession().setAttribute("jasperDs", helper);
		
		return mapping.findForward("printReport");
	}
	
	public ActionForward gerarTermoCredenciamentoTaxi(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		CadastroTurmaForm turmaForm = (CadastroTurmaForm) form;
		Turma turma = getTurmaDAO().consultar(turmaForm.getIdSelecionado());
		
		HashMap<String, Object> params = new HashMap<String, Object>();
		params.put("nomeDiretor", "Walace Petronio de Carvalho Lima");
		params.put("nomeInstrutor", turma.getInstrutor().getNome());
		String turmaDescricao = turma.getCodigoTaxi() + " - horário: " + turma.getPeriodo().getDescricaoPeriodo();
		params.put("turma", turmaDescricao);
		String diasDescricao = "";
		Integer mes = null;
		String nomeMes = null;
		for(CalendarioDia dia : turma.getCalendario()) {
			if(mes == null) {
				mes = dia.getData().getMonth();
				nomeMes = String.format(new Locale("pt","BR"), "%1$tB", dia.getData());
			} else if(mes != dia.getData().getMonth()) {
				diasDescricao += "de " + nomeMes + " e ";
				mes = dia.getData().getMonth();
				nomeMes = String.format(new Locale("pt","BR"), "%1$tB", dia.getData());
			}
			diasDescricao += String.format(new Locale("pt","BR"), "%1$td", dia.getData()) + " / ";			
		}
		diasDescricao = diasDescricao.substring(0, diasDescricao.length() -2) + "de " + nomeMes;
		params.put("dias", diasDescricao);
		
		request.getSession().setAttribute("reportType", Type.TERMO_CREDENCIAMENTO_TAXI);
		request.getSession().setAttribute("jasperParams", params);
		request.getSession().setAttribute("jasperDs", turma.getMatriculas());
		
		return mapping.findForward("printReport");
	}
	
	private void consultar(CadastroTurmaForm turmaForm, HttpServletRequest request) throws Exception {
		Turma vo = new Turma();
		
		if(turmaForm.getCurso() != null && turmaForm.getCurso() > 0) {
			vo.setCurso(new Curso(turmaForm.getCurso()));
		}
		if(turmaForm.getPeriodo() != null && !turmaForm.getPeriodo().equals("")) {
			vo.setPeriodo(Periodo.setValue(new Integer(turmaForm.getPeriodo())));
		}
		if(turmaForm.getDataInicio() != null && !turmaForm.getDataInicio().equals("")) {
			vo.setInicio(getDateFormatDojo().parse(turmaForm.getDataInicio()));
		}
		
		List<Turma> listaResultado = getTurmaDAO().consultar(vo);
		request.setAttribute("listaResultado", listaResultado);
	}
	
	public CalculoDataTurma getCalculoDataTurma() {
		return calculoDataTurma;
	}
	public void setCalculoDataTurma(CalculoDataTurma calculoDataTurma) {
		this.calculoDataTurma = calculoDataTurma;
	}
}
